import SEO from "../components/SEO";
import { TOC, TOCList, TOCLink } from "../components/TOC";

<SEO title="Rect" description="Measures a DOM node's bounding box in React" />

# Rect

<TOC>
	<TOCList>
		<TOCLink href="#userect">useRect</TOCLink>
		<TOCLink href="#rect-1">Rect</TOCLink>
	</TOCList>
</TOC>

Measures DOM elements (aka. bounding client rect). See also [Element.getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect)

## Installation

From the command line in your project directory, run `npm install @reach/rect` or `yarn add @reach/rect`. Then import the component or hook that you need:

```bash
npm install @reach/rect
# or
yarn add @reach/rect
```

```js
import { Rect, useRect } from "@reach/rect";
```

## Component API

### useRect

`function useRect<T extends Element>(nodeRef: React.RefObject<T>, options?: { observe?: boolean, onChange?: (rect: DOMRect) => void }): null | DOMRect`

Hook that observes and returns the measurements (ClientRect) of a DOM element. Pass it the ref that is placed on the element to be measured.

#### useRect Options

| Option                          | Type   | Required |
| ------------------------------- | ------ | -------- |
| [`observe`](#userect-observe)   | `bool` | false    |
| [`onChange`](#userect-onchange) | `func` | false    |

##### useRect `observe`

Tells `useRect` whether or not to observe changes to the position of the node. Defaults to `true`.

This is typically used for elements that pop over other elements. You generally don't need to observe all of the time—only when the popup is active.

If `observe` is false, the element's `DOMRect` will no longer be observed.

```jsx
// jsx-demo
function Example() {
	const [observe, setObserve] = React.useState(true);
	// your own ref
	const ref = React.useRef();

	// pass it in to be observered
	const rect = useRect(ref, { observe });

	return (
		<div>
			<button onClick={() => setObserve(!observe)}>
				{observe ? "Stop" : "Start"} observing
			</button>
			<pre>{JSON.stringify(rect, null, 2)}</pre>
			<div
				// and then place the ref
				ref={ref}
				contentEditable
				style={{
					display: "inline-block",
					padding: 10,
					border: "solid 1px",
				}}
				dangerouslySetInnerHTML={{
					__html: "Edit this to change the size!",
				}}
			/>
		</div>
	);
}
```

##### useRect `onChange`

`onChange?(rect: DOMRect): void`

Calls back whenever the `rect` of the element changes.

```jsx
function Example() {
	const ref = React.useRef();
	useRect(ref, {
		onChange(rect) {
			console.log(rect);
		},
	});
	return <div ref={ref} />;
}
```

### Rect

Render prop component for use in class components to observe element measurements.

#### Rect Props

| Prop                         | Type   | Required |
| ---------------------------- | ------ | -------- |
| [`children`](#rect-children) | `func` | true     |
| [`observe`](#rect-observe)   | `bool` | false    |
| [`onChange`](#rect-onchange) | `func` | false    |

##### Rect `children`

`children(args: { rect: DOMRect | null; ref: React.Ref<any> }): JSX.Element`

A function that calls back to you with a `ref` to place on an element and the `rect` measurements of the dom node.

**Note**: On the first render `rect` will be `null` because we can't measure a node that has not yet been rendered. Make sure your code accounts for this.

##### Rect `observe`

`observe?: boolean`

Same as [`useRect`'s `observe` option](#userect-observe). While observing, the `children` render prop may call back very quickly (especially while scrolling), so it can be important for performance to avoid observing when you don't need to. Defaults to `true`.

```jsx
<Rect observe={false}>
	{({ rect, ref }) => (
		<div ref={ref}>
			<div>Will not measure the element when false</div>
			<div>
				Edit this code and change it to <code>true</code>
			</div>
			<pre>{JSON.stringify(rect, null, 2)}</pre>
		</div>
	)}
</Rect>
```

##### Rect `onChange`

`onChange?(rect: DOMRect): void`

Same as [`useRect`'s `onChange` option](#userect-onchange).

```jsx
<Rect onChange={rect => console.log(rect)}/>
  {({ rect, ref }) => (
    <div ref={ref}/>
  )}
</Rect>
```
